package cn.iocoder.yudao.framework.excel.core.util;

import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Excel 工具类
 *
 * @author 芋道源码
 */
public class ExcelUtils {

    /**
     * 将列表以 Excel 响应给前端
     *
     * @param response  响应
     * @param filename  文件名
     * @param sheetName Excel sheet 名
     * @param head      Excel head 头
     * @param data      数据列表哦
     * @param <T>       泛型，保证 head 和 data 类型的一致性
     * @throws IOException 写入失败的情况
     */
    public static <T> void write(HttpServletResponse response, String filename, String sheetName,
                                 Class<T> head, List<T> data) throws IOException {
        String rq = "朝顺物流" + DateUtil.format(new Date(), "yyyy-MM-dd") + "运货单";
        //字体//字体大小
        WriteFont writeFont = new WriteFont();
        writeFont.setFontHeightInPoints((short)12);
        WriteCellStyle contentcellstyle = new WriteCellStyle();
        //左边框线//]顶部框线//右边框线//底部框线
        //字体//字体大小
        contentcellstyle.setHorizontalAlignment(HorizontalAlignment.CENTER);//文本居中
        contentcellstyle.setVerticalAlignment(VerticalAlignment.CENTER);
        contentcellstyle.setWriteFont(writeFont);
        contentcellstyle.setBorderLeft(BorderStyle.THIN);
        contentcellstyle.setBorderTop(BorderStyle.THIN);
        contentcellstyle.setBorderRight(BorderStyle.THIN);
        contentcellstyle.setBorderBottom(BorderStyle.THIN);
        //左边框线//]顶部框线//右边框线//底部框线
        ArrayList<WriteCellStyle> contentcells = new ArrayList<>();
        contentcells.add(contentcellstyle);
        //样式策略
        HorizontalCellStyleStrategy handler = new HorizontalCellStyleStrategy();
        handler.setContentWriteCellStyleList(contentcells);
        // 针对某一行做特殊处理
        // 设置指定行的样式
        // 输出 Excel
        EasyExcel.write(response.getOutputStream(), head)
                .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                .registerWriteHandler(new SheetWriteHandler() {
                    @Override
                    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
                        Sheet sheet = writeSheetHolder.getSheet();
                        Workbook workbook = writeWorkbookHolder.getWorkbook();

                        // 1. 插入标题行
                        Row titleRow = sheet.createRow(0); // 创建新第一行

                        // 2. 获取总列数（自动适配实体类字段数）
                        int columnCount = writeSheetHolder.getExcelWriteHeadProperty().getHeadMap().size();

                        // 3. 合并单元格（合并第一行的所有列）
                        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columnCount - 1));

                        // 3. 设置标题样式
                        // 创建字体对象
                        Font font = workbook.createFont();
                        // 设置字体加粗
                        font.setBold(true);
                        // 设置字体大小（默认11号，这里设置为14号）
                        font.setFontHeightInPoints((short) 30);
                        CellStyle style = workbook.createCellStyle();
                        style.setAlignment(HorizontalAlignment.CENTER);
                        style.setFont(font);
                        // ...（其他样式设置）

                        Cell titleCell = titleRow.createCell(0);
                        titleCell.setCellValue(rq);
                        titleCell.setCellStyle(style);
                    }
                })
                .registerWriteHandler(new CellWriteHandler() {
                    @Override
                    public void afterCellDispose(WriteSheetHolder sheetHolder, WriteTableHolder tableHolder,
                                                 List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

                        // 当处理到最后一行数据的最后一个单元格时，添加说明行(运单号等标题不算额外添加的，第一行的大标题才是，所以需要加1)
                        if (!isHead && cell.getRowIndex() == data.size() + 1) {
                            Sheet sheet = sheetHolder.getSheet();

                            // 1. 创建说明行（最后一行+1）
                            Row remarkRow = sheet.createRow(cell.getRowIndex() + 1);

                            // 4. 写入说明内容
                            Cell remarkCell = remarkRow.createCell(0);
                            remarkCell.setCellValue("发货次数：" + data.size());
                        }
                    }
                })
//                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度，自动适配。最大 255 宽度
                .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框
                .registerWriteHandler(handler) // 基于固定 sheet 实现下拉框
                .relativeHeadRowIndex(1)
                .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
                .registerWriteHandler(new SheetWriteHandler() { // 打印时添加分页
                    @Override
                    public void afterSheetCreate(WriteWorkbookHolder workbookHolder, WriteSheetHolder sheetHolder) {
                        Sheet sheet = sheetHolder.getSheet();

                        // 1. 获取PageSetup并设置页脚
                        sheet.getFooter().setCenter("第 &P 页"); // &P 表示页码

                        // 2. 设置打印相关属性（可选）
                        sheet.setAutobreaks(true); // 自动分页
//                        sheet.setFitToPage(true);  // 适应页面
                    }
                })
                .sheet(sheetName).doWrite(data);
        // 设置 header 和 contentType。写在最后的原因是，避免报错时，响应 contentType 已经被修改了
        response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
    }

    public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException {
        return EasyExcel.read(file.getInputStream(), head, null)
                .autoCloseStream(false)  // 不要自动关闭，交给 Servlet 自己处理
                .doReadAllSync();
    }

    public static <T> List<T> read(MultipartFile file, Class<T> head, Integer headRowNumber) throws IOException {
        return EasyExcel.read(file.getInputStream(), head, null)
                .autoCloseStream(false)  // 不要自动关闭，交给 Servlet 自己处理
                .headRowNumber(headRowNumber)
                .doReadAllSync();
    }

}
